package com.ding.dailyup.controller;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import com.ding.dailyup.entity.response.DailyRecommendResp;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ding.dailyup.annotation.LoginUser;
import com.ding.dailyup.constant.StockConstant;
import com.ding.dailyup.emum.StrategyStatusEnum;
import com.ding.dailyup.entity.JsonResult;
import com.ding.dailyup.entity.response.StockRecommendResp;
import com.ding.dailyup.entity.response.ZhishuResp;
import com.ding.dailyup.enums.StockImgLevelEnum;
import com.ding.dailyup.exception.BOException;
import com.ding.dailyup.model.StockRecommend;
import com.ding.dailyup.model.StockStrategy;
import com.ding.dailyup.model.UserBuyStrategy;
import com.ding.dailyup.model.UserCollectStock;
import com.ding.dailyup.redis.RedisService;
import com.ding.dailyup.service.StockRecommendService;
import com.ding.dailyup.service.StockStrategyService;
import com.ding.dailyup.service.UserService;
import com.ding.dailyup.util.StockUtil;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@RestController
@RequestMapping("/daily/stock")
@Api(tags = "每日股票")
public class StockController {
	private static Logger logger = LoggerFactory
			.getLogger(StockController.class);
	@Autowired
	private StockRecommendService stockRecommendService;
	@Autowired
	private UserService userService;
	@Autowired
	private StockStrategyService stockStrategyService;
	@Autowired
	private RedisService redisService;

	@GetMapping("/list")
	@ApiOperation(value = "每日股票查询")
	public JsonResult<List<StockRecommendResp>> getDailyStock(
			@ApiParam(value = "策略id") @RequestParam(value = "strategyId") Long strategyId,
			@ApiParam(value = "日期, 精确到时分秒, 转毫秒时间戳 ") @RequestParam(value = "dateTimestamp") long dateTimestamp,
			@LoginUser Long userId) {

		// 判断策略是否可用
		StockStrategy strategy = stockStrategyService.findById(strategyId);

		// 如果策略是收费的,
		if (!StrategyStatusEnum.usable(strategy.getStatus())) {
			// 查看是否购买过
			boolean buy = userService.getUserBuyStrategy(userId).stream()
					.map(UserBuyStrategy::getStrategyId)
					.anyMatch(i -> i.equals(strategyId));
			if (!buy) {
				throw new BOException("联系客服获取该策略");
			}
		}

		// 按照策略查询股票
		List<StockRecommend> recommend = stockRecommendService
				.findRecommend(strategyId, dateTimestamp);
		List<String> userCollectStocks = Lists.newArrayList();

		// 设置用户收藏状态
		if (userId != 0) {
			userCollectStocks = userService.listUserCollectStocks(userId)
					.stream().map(UserCollectStock::getStockCode)
					.collect(Collectors.toList());
		}
		List<String> finalUserCollectStocks = userCollectStocks;
		List<StockRecommendResp> rs = recommend.stream().map(item -> {
			StockRecommendResp resp = new StockRecommendResp();
			BeanUtil.copyProperties(item, resp);
			String raiseDownImgUrl = StockUtil.getRaiseDownImgUrl(
					item.getStockCode(), StockImgLevelEnum.DAILY.level(),
					System.currentTimeMillis());
			resp.setDailyRaiseAndFallImgUrl(raiseDownImgUrl);
			resp.setCollected(
					finalUserCollectStocks.contains(item.getStockCode()));
			resp.setStockCode(item.getStockCode());
			return resp;
		}).collect(Collectors.toList());
		return JsonResult.succResult(rs);
	}

    @GetMapping("/list/v2")
    @ApiOperation(value = "每日股票查询(多个策略查询交集)")
    public JsonResult<DailyRecommendResp> getDailyStockV2(
            @ApiParam(value = "策略id") @RequestParam(value = "strategyId") String strategyIds,
            @ApiParam(value = "日期, 精确到时分秒, 转毫秒时间戳 ") @RequestParam(value = "dateTimestamp") long dateTimestamp,
            @LoginUser Long userId) {
        if (StringUtils.isNotEmpty(strategyIds)) {
            Set<String> unionCodes = Sets.newHashSet();
            List<Long> strategyLongIds = Arrays.stream(strategyIds.split(","))
                    .filter(StringUtils::isNotEmpty).map(Long::parseLong)
                    .collect(Collectors.toList());
            Set<String> strategyDesc = Sets.newHashSet();
            for (Long strategyLongId : strategyLongIds) {
                StockStrategy strategy = stockStrategyService
                        .findById(strategyLongId);
                if (StrUtil.isNotEmpty(strategy.getStrategyDescription())) {
                    strategyDesc.addAll(Arrays.asList(
                            strategy.getStrategyDescription().split(";")));
                }
            }
            List<String> codes = Lists.newArrayList();
            for (int i = 0; strategyLongIds.size() > i; i++) {
                // StockRecommend
                Map<String, StockRecommend> dailyRecommend = stockRecommendService
                        .findRecommend(strategyLongIds.get(i), dateTimestamp)
                        .stream()
                        .collect(Collectors.toMap(StockRecommend::getStockCode,
                                Function.identity(), (key1, key2) -> key2));
                codes.addAll(dailyRecommend.keySet());
            }
            Map<String, Long> codeWithCount = codes.stream().collect(
                    Collectors.groupingBy(x -> x, Collectors.counting()));
            for (String code : codeWithCount.keySet()) {
                if (codeWithCount.get(code) == strategyLongIds.size()) {
                    unionCodes.add(code);
                }
            }
            List<String> userCollectStocks = Lists.newArrayList();

            // 设置用户收藏状态
            if (userId != 0) {
                userCollectStocks = userService.listUserCollectStocks(userId)
                        .stream().map(UserCollectStock::getStockCode)
                        .collect(Collectors.toList());
            }
            List<String> finalUserCollectStocks = userCollectStocks;

            Map<String, StockRecommend> stock = stockRecommendService
                    .findRecommend(unionCodes, dateTimestamp).stream()
                    .collect(Collectors.toMap(StockRecommend::getStockCode,
                            Function.identity(), (key1, key2) -> key2));
            List<StockRecommendResp> rs = stock.values().stream().map(item -> {
                StockRecommendResp resp = new StockRecommendResp();
                BeanUtil.copyProperties(item, resp);
                String raiseDownImgUrl = StockUtil.getRaiseDownImgUrl(
                        item.getStockCode(), StockImgLevelEnum.DAILY.level(),
                        System.currentTimeMillis());
                resp.setDailyRaiseAndFallImgUrl(raiseDownImgUrl);
                resp.setCollected(
                        finalUserCollectStocks.contains(item.getStockCode()));
                resp.setStockCode(item.getStockCode());
                return resp;
            }).collect(Collectors.toList());
            return JsonResult.succResult(new DailyRecommendResp(rs,
                    Joiner.on("；").join(strategyDesc)));
        }

        return JsonResult
                .succResult(new DailyRecommendResp(Lists.newArrayList(), ""));
    }

	// 每日股票上传
	@PostMapping(value = "/upload")
	// @ApiOperation(value = "每日股票上传")
	public JsonResult uploadDailyStock(
			@ApiParam(value = "上传每日推荐股票") @RequestBody JSONObject stockUpload,
			HttpServletRequest request) {
		String adminToken = request.getHeader("adminToken");

		// 验证权限
		if ("dingguanghui888".equals(adminToken)) {
			DateTimeFormatter df = DateTimeFormatter
					.ofPattern("yyyy-MM-dd HH:mm:ss");
			LocalDateTime date = StrUtil
					.isNotBlank(stockUpload.getString("uploadDate"))
							? LocalDateTime.parse(
									stockUpload.getString("uploadDate"), df)
							: LocalDateTime.now();
			JSONArray dataArray = stockUpload.getJSONArray("data");
			for (int i = 0; i < dataArray.size(); i++) {
				JSONObject jsonObject = dataArray.getJSONObject(i);
				Long strategyId = jsonObject.getLong("strategyId");
				List<String> stockCodes = JSONObject.parseArray(
						jsonObject.getJSONArray("stockCodes").toJSONString(),
						String.class);
				logger.info("开始上传个股,策略id:{},个股信息:{}", strategyId,
						Joiner.on(",").join(stockCodes));
				stockRecommendService.uploadStock(strategyId, date, stockCodes);
			}
		} else {
			throw new BOException("管理员接口权限检查异常");
		}
		return JsonResult.succResult();
	}

	@GetMapping("/zhishu")
	@ApiOperation(value = "获取指数")
	public JsonResult<List<ZhishuResp>> listZhishu() {
		List<String> codesWithHouse = Lists.newArrayList(StockConstant.SHANGHAI,
				StockConstant.SHENZHENG, StockConstant.CHUANGYE);
		String resp = HttpUtil.get(StockConstant.QT_STOCK_URL
				+ Joiner.on(",").join(codesWithHouse));
		String[] raws = resp.split("\n");
		List<ZhishuResp> zhishu = Lists.newArrayList();

		if (codesWithHouse.size() != raws.length) {
			return JsonResult.succResult(zhishu);
		}
		for (int i = 0; i < codesWithHouse.size(); i++) {
			String symbol = codesWithHouse.get(i);
			String raw = raws[i];
			String assertion = String.format("(?<=v_%s=\").*?(?=\";)", symbol);
			Pattern pattern = Pattern.compile(assertion);
			Matcher matcher = pattern.matcher(raw);
			while (matcher.find()) {
				String[] metas = matcher.group().split("~");
				zhishu.add(new ZhishuResp(metas[1], metas[2], metas[3],
						metas[32]));
			}
		}
		return JsonResult.succResult(zhishu);
	}

	@GetMapping("/max/recommend/timestamp")
	@ApiOperation(value = "获取最大推送日期, 时间戳")
	public JsonResult getMaxRecommendTime() {
		return JsonResult.succResult(redisService.getMaxRecommendTime());
	}

}
